﻿using AutoMapper;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Zhao.Common.Helper;
using Zhao.IServer;
using Zhao.IServer.User;
using Zhao.Models.DTO;
using Zhao.Models.Entity;
using Zhao.Repository.Base;
using Zhao.Repository.UnitOfWork;

namespace Zhao.Service.User
{
    /// <summary>
    /// 角色表（RBAC权限控制）
    ///</summary>
    public class RolesServer : BaseService<Roles>, IRolesServer
    {
        private readonly IUnitOfWork _unitOfWork;
        private readonly IMapper _IMapper;
        public RolesServer(IBaseRepository<Roles> baseDal, IUnitOfWork unitOfWork, IMapper IMapper) : base(baseDal, unitOfWork)
        {
            _unitOfWork = unitOfWork;   
            _IMapper = IMapper;
        }


        /// <summary>
        /// 获取所有的菜单信息
        /// 根据角色判断，菜单是否归属于某个角色
        /// </summary>
        /// <param name="roleId"></param>
        /// <returns></returns>
        public async Task<(List<MenuDTO>, List<Guid>)> GetAllMenuTreeListAsync(int roleId)
        {
            //查询菜单数据--延迟加载
            var treeMeueList = _Client
                .Queryable<Menus>()
                .Select(m1 => new Menus
                {
                    Id = m1.Id,
                    ParentId = m1.ParentId,
                    MenuText = m1.MenuText,
                    WebUrlName = m1.WebUrlName,
                    VueFilePath = m1.VueFilePath,
                    Icon = m1.Icon,
                    WebUrl = m1.WebUrl,
                    IsLeafNode = m1.IsLeafNode,
                    OrderBy = m1.OrderBy,
                    CreateTime = m1.CreateTime,
                    UpdateTime = m1.UpdateTime,
                    IsDeleted = m1.IsDeleted,
                    Status = m1.Status
                });

            //生成树结构数据
            var treeDataList = await treeMeueList.ToTreeAsync(it => it.Children, it => it.ParentId, default(Guid));


            //属于某角色的菜单Id(找出所属菜单的id)
            List<Guid> menuIds = await _Client.Queryable<RoleMenuMap>()
             .Where(c => c.RoleId.Equals(roleId))
             .Select(m => m.MenuId).ToListAsync(); //拿到该角色的菜单id

            ////找出属于某一个角色的叶节点菜单  拿到对应的叶节点菜单id和数量
            var leafNodeMenuIds = treeMeueList
                .Where(c => c.IsLeafNode == true && menuIds.Contains(c.Id))
                .GroupBy(c => c.ParentId)//要根据对应的id排血
                .Select(c => new { menid = SqlFunc.AggregateMax(c.ParentId), count = SqlFunc.AggregateCount(c.Id) }).ToList();

            ////全量---没有角色归属
            var allmenIdlist = _Client.Queryable<Menus>().Where(b => menuIds.Contains(b.ParentId)).GroupBy(c => c.ParentId)
                     .Select(c => new { menid = SqlFunc.AggregateMax(c.ParentId), count = SqlFunc.AggregateCount(c.Id) })
                     .ToList();
            ////不能返回的叶节点菜单Id
            List<Guid> delMenuids = new List<Guid>();
            foreach (var menId in allmenIdlist)
            {
                var model = leafNodeMenuIds.FirstOrDefault(c => c.menid == menId.menid);
                if (model != null && model.count < menId.count)  //按钮并没有被全选
                {
                    delMenuids.Add(model.menid);
                }
            }

            ////开始递归找出父级
            List<Guid> delAllMenuids = new List<Guid>();

            var data = _Client.Queryable<Menus>()
               .Where(m => menuIds.Contains(m.Id)).ToList();

            //如果叶节点的菜单Id不返回，那么这个菜单的上级菜单，上上级菜单，。。。。。
            //都不应该返回
            foreach (var menuid in delMenuids)
            {
                GetParent(menuid, data, delAllMenuids);
            }

            ////开始移除不返回的菜单Id,包含的有叶节点，也有非叶节点
            foreach (var deid in delAllMenuids)
            {
                menuIds.Remove(deid);
            }

            List<MenuDTO> resultList = _IMapper.Map<List<Menus>, List<MenuDTO>>(treeDataList);

            return await Task.FromResult((resultList, menuIds));
        }

        /// <summary>
        /// 找父级Id
        /// </summary>
        /// <param name="menuId"></param>
        /// <param name="allmenuList"></param>
        /// <param name="delmenuids"></param>
        private void GetParent(Guid menuId, List<Menus> allmenuList, List<Guid> delmenuids)
        {
            Menus currentMenu = allmenuList.FirstOrDefault(c => c.Id == menuId);
            if (currentMenu != null)
            {
                delmenuids.Add(currentMenu.Id);
                Menus parentMenu = allmenuList.FirstOrDefault(c => c.Id == currentMenu.ParentId);
                if (parentMenu != null)
                {
                    GetParent(parentMenu.Id, allmenuList, delmenuids);
                }
            }
        }




        /// <summary>
        ///  设置角色菜单
        /// </summary>
        /// <param name="roleId"></param>
        /// <param name="menuIds"></param> 
        /// <returns></returns>
        public ApiResult SetRoleMenus(int roleId, List<Guid> menuIds)
        {
            Roles role =base._baseDal.Query(x=>x.RoleID== roleId);
            if (role == null)
            {
                return new ApiResult()
                {
                    Success = false,
                    Message = "角色Id不存在"
                };
            }
            var mmenuQuery = _Client.Queryable<Menus>().Where(r => menuIds.Contains(r.Id));

            List<Guid> existsMenus = mmenuQuery.Select(c => c.Id)
                .Distinct()
                .ToList();

            //得到要插入数据库的集合--角色菜单的关系数据
            List<RoleMenuMap> roleMenuMaplist = existsMenus.Select(r => new RoleMenuMap()
            {
                RoleId = roleId,
                MenuId = r
            }).ToList();


            //开始事务
            var result = _Client.AsTenant().UseTran(() =>
            {
                //先删除该角色现有的所有菜单
                _Client.Deleteable<RoleMenuMap>(m => m.RoleId == roleId).ExecuteCommand();
                //进行重新添加
                _Client.Insertable(roleMenuMaplist).ExecuteCommand();

                return true;// 返回值等行result.Data
            });

            if (result.Data == false) //返回值为false
            {
                return new ApiResult() { Success = false, Message = result.ErrorMessage };
            }
            else
            {
                return new ApiResult() { Success = true, Message = "操作成功" };
            }
        }

    }
}
